package com.yang.usb;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.yang.usb.receiver.OpenDevicesReceiver;
import com.yang.usb.util.FileUtil;
import com.yang.usbserial.util.HexDump;
import com.yang.usbserial.util.LogUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * USBHOST主机端
 */
public class UsbhostaoaActivity extends AppCompatActivity implements OpenDevicesReceiver.OpenDevicesListener, View.OnClickListener {
    private static final int CONNECTED_SUCCESS = 0;
    private static final int RECEIVER_MESSAGE_SUCCESS = 1;
    private static final int SEND_MESSAGE_SUCCESS = 2;

    private static final int SEND_MESSAGE_SUCCESS_FILE = 3;
    private static final String USB_ACTION = "com.yang.usb.host";
    private ExecutorService mThreadPool;
    private UsbManager mUsbManager;
    private OpenDevicesReceiver mOpenDevicesReceiver;
    private UsbDeviceConnection mUsbDeviceConnection;
    private UsbEndpoint mUsbEndpointOut;
    private UsbEndpoint mUsbEndpointIn;
    private boolean mToggle = true;
    private boolean isDetached = false;
    private final byte[] mBytes = new byte[64];
    private boolean isReceiverMessage = true;
    private UsbInterface mUsbInterface;
    private final StringBuffer mStringBuffer = new StringBuffer();
    private Context mContext;
    private boolean isfile = false;

    private static final int MAX_CHUNK_SIZE = 1024; // 块大小
    private byte[] currentFileData; // 当前文件数据
    private int currentOffset = 0; // 当前偏移
    String downloadFolderPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
    private List<byte[]> binFiles = new ArrayList<>();
    private int currentFileIndex = 1;

    private static final int MAX_RETRIES = 3; // 最大重试次数
    private int currentRetries = 0; // 当前重试次数

    private static final int CHUNK_SIZE = 1024;
    private boolean sendingData = false;
    private byte[] lastSentDataBlock; // 保存上一次发送的数据块
    private int fileDataSize = 0;
    private HandlerThread sendThread;
    private Handler sendHandler;
    private static final int YOUR_VENDOR_ID = 0x0483; // 替换成你的设备供应商ID
    private static final int YOUR_PRODUCT_ID = 0x5750; // 替换成你的设备产品ID

    private boolean isSendingData = false;

    private Button hostsendmessage, USBUpdate;
    private EditText hostmessage;

    private TextView hostlog, hosterror;

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case CONNECTED_SUCCESS://主机和服务端连接成功
                    hosterror.setText("");
                    hostsendmessage.setEnabled(true);
                    hostsendmessage.setText("USB已经连接");
                    loopReceiverMessage();
                    break;
                case RECEIVER_MESSAGE_SUCCESS://成功接受到数据
                    String contn = new String(mBytes, 0, (int) msg.obj);
                    hostlog.setText(contn);
                    if ("4F4B".equals(contn)) {
                        // 下位机准备好，开始发送文件内容
                        LogUtils.e("开始发文件");
                        isfile = true;
                        currentOffset = 0;
                        currentFileIndex = 0;
                        sendingData = false;
                        currentFileData = binFiles.get(currentFileIndex);
//                        sendDataChunk();
                        startSendThread();
                    }
                    break;
                case SEND_MESSAGE_SUCCESS://成功发送数据
                    if (currentFileData != null && currentFileData.length > 0) {
                        hostlog.setText((fileDataSize / currentFileData.length) * 100 + "%");
                    }
//                    mBinding.hostmessage.setText("发送成功");
                    break;
                case SEND_MESSAGE_SUCCESS_FILE:
                    hostlog.setText("文件发送完成");
                    break;
            }
        }
    };

    private void startSendThread() {
        sendThread = new HandlerThread("SendThread");
        sendThread.start();
        sendHandler = new Handler(sendThread.getLooper());
    }

    private void stopSendThread() {
        if (sendThread != null) {
            sendThread.quitSafely();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_usbhostaoa);
        hostsendmessage = findViewById(R.id.hostsendmessage);
        hostsendmessage.setOnClickListener(this);
        USBUpdate = findViewById(R.id.USBUpdate);
        USBUpdate.setOnClickListener(this);
        mContext = getApplicationContext();
        hostsendmessage.setEnabled(false);
        hostsendmessage.setText("没有连接USB");
        hostmessage = findViewById(R.id.hostmessage);
        hostlog = findViewById(R.id.hostlog);
        hosterror = findViewById(R.id.hosterror);

        mThreadPool = Executors.newFixedThreadPool(5);

        mUsbManager = (UsbManager) getSystemService(USB_SERVICE);
        // 初始化文件数据
        binFiles = FileUtil.readFilesFromDownloadFolder();
        openDevices();
    }


    /**
     * 打开设备 , 让主机和服务端连起来
     */
    private void openDevices() {
        LogUtils.e("打开设备");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
                0, new Intent(USB_ACTION), 0);
        IntentFilter intentFilter = new IntentFilter(USB_ACTION);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        mOpenDevicesReceiver = new OpenDevicesReceiver(this);
        registerReceiver(mOpenDevicesReceiver, intentFilter);

        //列举设备(手机)
        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        if (deviceList != null) {
            for (UsbDevice usbDevice : deviceList.values()) {
                int productId = usbDevice.getProductId();
                if (productId != 377 && productId != 7205) {
                    if (mUsbManager.hasPermission(usbDevice)) {
                        initAccessory(usbDevice);
                    } else {
                        mUsbManager.requestPermission(usbDevice, pendingIntent);
                    }
                }
            }
        } else {
            hosterror.setText((CharSequence) "请连接USB");
        }
    }

    /**
     * 发送命令 , 让手机进入Accessory模式
     *
     * @param usbDevice
     */
    private void initAccessory(UsbDevice usbDevice) {
        LogUtils.e("发送命令 , 让手机进入Accessory模式");
        UsbDeviceConnection usbDeviceConnection = mUsbManager.openDevice(usbDevice);
        if (usbDeviceConnection == null) {
            hosterror.setText("请连接USB");
            return;
        }
        //根据AOA协议打开Accessory模式
        initStringControlTransfer(usbDeviceConnection, 0, "Google, Inc."); // MANUFACTURER
        initStringControlTransfer(usbDeviceConnection, 1, "AccessoryChat"); // MODEL
        initStringControlTransfer(usbDeviceConnection, 2, "Accessory Chat"); // DESCRIPTION
        initStringControlTransfer(usbDeviceConnection, 3, "1.0"); // VERSION
        initStringControlTransfer(usbDeviceConnection, 4, "http://www.android.com"); // URI
        initStringControlTransfer(usbDeviceConnection, 5, "0123456789"); // SERIAL
        usbDeviceConnection.controlTransfer(0x40, 0x53, 0, 0, new byte[]{}, 0, 100);
//        usbDeviceConnection.close();
        LogUtils.e("initAccessory success(初始化客户端成功)");
        initDevice();
    }

    private void initStringControlTransfer(UsbDeviceConnection deviceConnection, int index, String string) {
        deviceConnection.controlTransfer(0x40, 52, 0, index, string.getBytes(), string.length(), 100);
    }

    /**
     * 初始化设备(手机) , 当手机进入Accessory模式后 , 手机的PID会变为Google定义的2个常量值其中的一个 ,
     */
    private void initDevice() {
        mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                while (mToggle) {
                    SystemClock.sleep(1000);
                    HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
                    Collection<UsbDevice> values = deviceList.values();
                    if (!values.isEmpty()) {
                        for (UsbDevice usbDevice : values) {
                            //方法获取Android连接的USB设备的唯一ID
                            int productId = usbDevice.getProductId();
                            if (productId == 0x2D00 || productId == 0x2D01 || productId == 0x2D02 ||
                                    productId == 0x2D03 || productId == 0x2D04 || productId == 0x2D05) {
                                LogUtils.e("连接设备是否进入id" + productId);
                                if (mUsbManager.hasPermission(usbDevice)) {//判断你的应用程序是否有接入此USB设备的权限，如果有则返回真，否则返回false.
                                    mUsbDeviceConnection = mUsbManager.openDevice(usbDevice);
                                    if (mUsbDeviceConnection != null) {
                                        mUsbInterface = usbDevice.getInterface(0);
                                        int endpointCount = mUsbInterface.getEndpointCount();
                                        for (int i = 0; i < endpointCount; i++) {
                                            UsbEndpoint usbEndpoint = mUsbInterface.getEndpoint(i);
                                            if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {// --块传输
                                                if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                                                    mUsbEndpointOut = usbEndpoint;
                                                } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                                                    mUsbEndpointIn = usbEndpoint;
                                                }
                                            } else if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_NUMBER_MASK) {///* in bmAttributes */

                                            } else if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_ISOC) {//--等时传输

                                            } else if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
                                                if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                                                    mUsbEndpointOut = usbEndpoint;
                                                } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                                                    mUsbEndpointIn = usbEndpoint;
                                                }
                                            }
                                        }
                                        if (mUsbEndpointOut != null && mUsbEndpointIn != null) {
                                            LogUtils.e("connected success(连接成功)");
                                            mHandler.sendEmptyMessage(CONNECTED_SUCCESS);
                                            mToggle = false;
                                            isDetached = true;
                                        }
                                    }
                                } else {
                                    //向USB设备请求临时的接入权限
                                    mUsbManager.requestPermission(usbDevice,
                                            PendingIntent.getBroadcast(mContext, 0,
                                                    new Intent(""), 0));
                                }
                            } else if (usbDevice.getVendorId() == YOUR_VENDOR_ID && usbDevice.getProductId() == YOUR_PRODUCT_ID) {
                                LogUtils.e("进入指定的设备");
                                if (mUsbManager.hasPermission(usbDevice)) {//判断你的应用程序是否有接入此USB设备的权限，如果有则返回真，否则返回false.
                                    mUsbDeviceConnection = mUsbManager.openDevice(usbDevice);
                                    if (mUsbDeviceConnection != null) {
                                        mUsbInterface = usbDevice.getInterface(0);
                                        mUsbDeviceConnection.claimInterface(mUsbInterface, true);
                                        int endpointCount = mUsbInterface.getEndpointCount();
                                        LogUtils.e("cs" + endpointCount);
                                        for (int i = 0; i < endpointCount; i++) {
                                            UsbEndpoint usbEndpoint = mUsbInterface.getEndpoint(i);
                                            if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {// --块传输
                                                if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                                                    mUsbEndpointOut = usbEndpoint;
                                                } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                                                    mUsbEndpointIn = usbEndpoint;
                                                }
                                            } else if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_NUMBER_MASK) {///* in bmAttributes */

                                            } else if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_ISOC) {//--等时传输

                                            } else if (usbEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {//-中断传输
                                                LogUtils.e("进入中断传输");
                                                if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
                                                    LogUtils.e("进入中断传输1");
                                                    mUsbEndpointOut = usbEndpoint;
                                                } else if (usbEndpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                                                    LogUtils.e("进入中断传输2");
                                                    mUsbEndpointIn = usbEndpoint;
                                                }
                                            }
                                        }
                                        if (mUsbEndpointOut != null && mUsbEndpointIn != null) {
                                            LogUtils.e("connected success(连接成功)");
                                            mHandler.sendEmptyMessage(CONNECTED_SUCCESS);
                                            mToggle = false;
                                            isDetached = true;
                                        }
                                    }
                                } else {
                                    //向USB设备请求临时的接入权限
                                    mUsbManager.requestPermission(usbDevice,
                                            PendingIntent.getBroadcast(mContext, 0,
                                                    new Intent(""), 0));
                                }
                            }
                        }
                    } else {
                        finish();
                    }
                }
            }
        });
    }

    /**
     * 接受消息线程 , 此线程在设备(手机)初始化完成后 , 就一直循环接受消息
     */
    private void loopReceiverMessage() {
        mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                while (isReceiverMessage) {
                    if (isfile) {
                        if (!isSendingData) {
                            // Set the flag to indicate that data is being sent
                            isSendingData = true;
                            sendDataChunk();

                            // Reset the flag after data has been sent
                            isSendingData = false;
                        }
                    } else {
                        /**
                         * 循环接受数据的地方 , 只接受byte数据类型的数据
                         */
                        if (mUsbDeviceConnection != null && mUsbEndpointIn != null) {
                            int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpointIn, mBytes, mBytes.length, -1);
                            if (i > 0) {
                                Message msg = new Message();
                                msg.what = RECEIVER_MESSAGE_SUCCESS;
                                msg.obj = i;
                                mHandler.sendMessage(msg);
                            }
                        }
                    }
                }
            }
        });
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.hostsendmessage) {
            sendDataToUSBDevice(hostmessage.getText().toString());
        } else if (v.getId() == R.id.USBUpdate) {
            startUsbCommunication();
        }
    }

    @Override
    public void openAccessoryModel(UsbDevice usbDevice) {
        initAccessory(usbDevice);
    }

    @Override
    public void openDevicesError() {
        hosterror.setText("USB连接错误");
    }

    @Override
    public void usbDetached() {
        if (isDetached) {
            finish();
        }
    }

    @Override
    protected void onDestroy() {
        stopSendThread();
        // 停止接收消息线程
        isReceiverMessage = false;

        // 关闭线程池
        if (mThreadPool != null && !mThreadPool.isShutdown()) {
            mThreadPool.shutdownNow();
        }
        mHandler.removeCallbacksAndMessages(null);
        super.onDestroy();

        if (mUsbDeviceConnection != null) {
            mUsbDeviceConnection.releaseInterface(mUsbInterface);
            mUsbDeviceConnection.close();
            mUsbDeviceConnection = null;
        }
        mUsbEndpointIn = null;
        mUsbEndpointOut = null;
        mToggle = false;
        unregisterReceiver(mOpenDevicesReceiver);
    }

    /**
     * 主机端发送数据
     */
    private void sendDataToUSBDevice(String data) {
        // 在这里实现向USB设备发送数据的逻辑
        // 使用usbDevice和endpointOut来发送数据
        // 这里仅供示例，需要根据实际情况来实现
        mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                if (mUsbDeviceConnection != null && mUsbEndpointOut != null) {
                    byte[] bytes = data.getBytes();
                    int bytesSent = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, bytes, bytes.length, 1000);
                    if (bytesSent < 0) {
                        LogUtils.e("发送数据失败。");
                    } else {
                        LogUtils.e("发送数据成功长度：" + bytesSent);
                        mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS);
                    }
//                    byte[] bytes = data.getBytes();
//                    int bytesWritten = 0;
//                    while (bytesWritten < bytes.length) {
//                        int writeLength = Math.min(bytes.length - bytesWritten, mUsbEndpointOut.getMaxPacketSize());
//                        byte[] chunk = new byte[writeLength];
//                        System.arraycopy(bytes, bytesWritten, chunk, 0, writeLength);
//                        int result = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut, chunk, writeLength, 1000);
//                        if (result < 0) {
//                            LogUtils.e("发送数据失败");
//                            break;
//                        } else {
//                            mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS);
//                        }
//                        bytesWritten += result;
//                    }
                }
            }
        });
    }

    private void sendDataToUSBDevice(byte[] data) {
        LogUtils.e("真正发送的长度" + data.length);
        fileDataSize = fileDataSize + data.length;
        if (mUsbDeviceConnection != null && mUsbEndpointOut != null) {
            int i = mUsbDeviceConnection.bulkTransfer(mUsbEndpointOut,
                    data, data.length, 1000);
            if (i > 0) {//大于0表示发送成功
                mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS);
            } else {
                LogUtils.e("发送数据失败");
            }
            // 处理下位机的响应
            int result = mUsbDeviceConnection.bulkTransfer(mUsbEndpointIn, mBytes, mBytes.length, 1000);
            if (result > 0) {
                String response = new String(mBytes, 0, result);
                handleResponse(response);
            }
        }
    }


    /**
     * 文件信息发送
     */
    private void startUsbCommunication() {
        // 构建命令，包含文件大小信息
        String command = buildCommand();
        LogUtils.e(HexDump.convertToHexAndSendData(command));
        // 发送命令给下位机，等待下位机准备好
        sendDataToUSBDevice(HexDump.convertToHexAndSendData(command));

    }

    private String buildCommand() {
        // 构建命令，格式为 "USB_Update;文件1的大小;文件2的大小;文件3的大小;"
        StringBuilder commandBuilder = new StringBuilder("USB_Update;");
        for (byte[] binFileData : binFiles) {
            int fileSize = binFileData.length;
            commandBuilder.append(fileSize).append(";");
        }
        LogUtils.e(commandBuilder.toString());
        return commandBuilder.toString();
    }

    private void sendDataChunk() {
        if (!sendingData) {
            sendingData = true;
            sendHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (currentFileData == null) {
                        // 当前文件数据为空，表示所有文件已经发送完成
//                        sendDataToUSBDevice("结束");
                        mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS_FILE);
                        return;
                    }

                    if (currentOffset >= currentFileData.length) {
                        // 当前文件数据已发送完成，切换到下一个文件
                        LogUtils.e("当前文件数据已发送完成，切换到下一个文件");
                        currentOffset = 0;
                        currentFileIndex++;
                        Message msg = new Message();
                        msg.what = SEND_MESSAGE_SUCCESS;
                        msg.obj = 100;
                        mHandler.sendMessage(msg);
                        if (currentFileIndex < binFiles.size()) {
                            currentFileData = binFiles.get(currentFileIndex);
                            fileDataSize = 0;
                            Message msg1 = new Message();
                            msg1.what = SEND_MESSAGE_SUCCESS;
                            msg1.obj = 0;
                            mHandler.sendMessage(msg1);
                        } else {
                            LogUtils.e("发送完成");
                            currentFileData = null;
                            isReceiverMessage = false;
                        }
                    }

                    if (currentFileData != null) {
                        int chunkSize = Math.min(CHUNK_SIZE, currentFileData.length - currentOffset);
                        byte[] chunkData = new byte[chunkSize];
                        System.arraycopy(currentFileData, currentOffset, chunkData, 0, chunkSize);


                        // 计算并发送LRC检验
                        byte lrc = calculateLRC(chunkData);
                        LogUtils.e("发送过去的 LRC: " + lrc);

                        // 合并数据块和LRC
                        byte[] dataWithLRC = new byte[chunkSize + 1];
                        System.arraycopy(chunkData, 0, dataWithLRC, 0, chunkSize);
                        dataWithLRC[chunkSize] = lrc;

                        // 保存上一次发送的数据块
                        lastSentDataBlock = dataWithLRC;

                        // 发送数据
                        sendDataToUSBDevice(dataWithLRC);

                        // 接收下位机的响应
                        int result = mUsbDeviceConnection.bulkTransfer(mUsbEndpointIn, mBytes, mBytes.length, 1000);
                        if (result > 0) {
                            String response = new String(mBytes, 0, result);
                            handleResponse(response);
                        } else {
                            if (currentRetries < MAX_RETRIES) {
                                LogUtils.e("发送失败重新发送");
                                if (lastSentDataBlock != null) {
                                    sendDataToUSBDevice(lastSentDataBlock);
                                }
                            } else {
                                // 达到最大重试次数，处理错误
                                LogUtils.e("达到最大重试次数，无法继续重发");
                                // 处理错误情况，例如中断通信或其他操作
                            }

                        }
                    }
                    sendingData = false;
                }
            });
        }
    }

    private void handleResponse(String response) {
        if ("4F4B".equals(response)) {
            currentOffset += CHUNK_SIZE; // 数据传输成功，继续下一个数据块
            sendingData = false;
            isSendingData = false;
        } else if ("455252".equals(response)) {
            if (currentRetries < MAX_RETRIES) {
                LogUtils.e("发送失败重新发送");
                if (lastSentDataBlock != null) {
                    sendDataToUSBDevice(lastSentDataBlock);
                }
            } else {
                // 达到最大重试次数，处理错误
                LogUtils.e("达到最大重试次数，无法继续重发");
                // 处理错误情况，例如中断通信或其他操作
            }
        } else if ("454E44".equals(response)) {
            stopSendThread();
            // 停止接收消息线程
            isReceiverMessage = false;
            mHandler.sendEmptyMessage(SEND_MESSAGE_SUCCESS_FILE);
        }
    }


    private byte calculateLRC(byte[] data) {
        byte lrc = 0;
        for (byte b : data) {
            lrc ^= b;
        }
        return lrc;
    }

}